<<<<<<< HEAD
package main

import (
	"bufio"
	"bytes"
	"encoding/json"
	"fmt"
	_ "image/jpeg"
	"image/png"
	"io"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/jung-kurt/gofpdf"
	"golang.org/x/image/tiff"

	"github.com/gin-gonic/gin"
)

// **************全局变量定义**************
// 定义全局扫描进度变量ScanProgressValue
var ScanProgressValue float64 = 0.0

// 定义全局扫描文件存储目录变量DEST_DIR
var DEST_DIR string = "./templates/scanData"

// 定义全局网页端口变量PORT
var POST string = "7575"

// 定义全局扫描时间是否存在检测变量
var ScanTimeExist bool = false

// 定义全局扫描时间变量
var ScanTimeStart time.Time
var ScanTimeEnd time.Time
var ScanTimeAll float64

// 定义全局扫描流程结束标识符
var ScanEnd string = "0"

//***************************************

// *************后端函数定义**************
// 执行SANE扫描cmd命令并返回实时扫描进度
func ScanProgress(device string, dpi string, mode string, fileName string) (float64, error) {
	ScanEnd = "0"
	//声明TIF_DEST变量
	TIF_DEST := DEST_DIR + "/" + fileName + ".tiff"
	//声明PDF_DEST变量
	PDF_DEST := DEST_DIR + "/" + fileName + ".pdf"
	//声明TBN_DEST变量
	TBN_DEST := DEST_DIR + "/thumb/" + fileName + ".png"
	cmdName := "scanimage"
	cmdArgs := []string{"--progress", "--device-name", device, "--resolution", dpi, "--mode", mode, "--format", "tiff", "--output-file", TIF_DEST} // --device-name设备名称 --resolution分辨率 --mode扫描模式 --progress命令用于显示扫描的进度

	// 打印即将执行的命令
	fmt.Printf("将要执行的命令：%s %s\n", cmdName, strings.Join(cmdArgs, " "))
	ScanProgressValue = 60.00
	cmd := exec.Command(cmdName, cmdArgs...)
	var stderr bytes.Buffer
	cmd.Stderr = &stderr
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		fmt.Printf("执行cmd.StdoutPipe()出错:%s\n", err)
		fmt.Println(fmt.Sprint(err) + ": " + stderr.String())
		return 0, err
	}

	if err := cmd.Start(); err != nil {
		fmt.Printf("执行cmd.Start()出错:%s\n", err)
		fmt.Println(fmt.Sprint(err) + ": " + stderr.String())
		return 0, err
	}

	go func() {
		reader := bufio.NewReader(stdout)
		for {
			line, err := reader.ReadString('\n')
			fmt.Printf("当前行内容：%s\n", line) // 添加调试输出

			if err != nil || err == io.EOF {
				break
			}

			if strings.Contains(line, "Progress:") {
				fmt.Printf("发现进度信息：%s\n", line) // 添加调试输出

				progressStr := strings.Split(line, ":")[1]
				// 去除百分号
				progressStr = strings.TrimSpace(progressStr[:len(progressStr)-1])

				progress, err := strconv.ParseFloat(progressStr, 64)
				if err != nil {
					fmt.Println("解析进度信息时出现错误:", err) // 添加调试输出
					// 如果解析出错，可以尝试打印 progressStr 看看原始内容
					continue
				}

				fmt.Printf("当前 ScanProgressValue：%f\n", progress)
				// 将进度保存到全局变量
				ScanProgressValue = progress
			}
		}
	}()

	if err := cmd.Wait(); err != nil {
		fmt.Printf("执行cmd.Wait()出错:%s\n", err)
		fmt.Println(fmt.Sprint(err) + ": " + stderr.String())
		return 0, err
	}
	ScanProgressValue = 100.00
	fmt.Printf("tiff格式转换...")
	//将获得的tiff转换
	//转为pdf
	command1 := "convert"
	args1 := []string{TIF_DEST, PDF_DEST}
	cmd1 := exec.Command(command1, args1...)
	err1 := cmd1.Run()
	if err1 != nil {
		fmt.Printf("执行tiff转pdf出错: %s", err1)
		fmt.Println("尝试使用golang转换pdf...")
		// 读取 TIF 文件
		tifData, err := os.ReadFile(TIF_DEST)
		if err != nil {
			fmt.Println("Error reading TIF file:", err)

		}

		// 解码 TIF 数据
		img, err := tiff.Decode(bytes.NewReader(tifData))
		if err != nil {
			fmt.Println("Error decoding TIF image:", err)

		}

		// 获取 TIF 图像的宽度和高度
		bounds := img.Bounds()
		imageWidth := float64(bounds.Dx())
		imageHeight := float64(bounds.Dy())

		// 创建 PDF 文件
		pdf := gofpdf.New("P", "mm", "A4", "")
		pdf.AddPage()

		// 将 TIF 图像转换为 PDF 图像
		imageIndex := pdf.RegisterImageOptions(TIF_DEST, gofpdf.ImageOptions{ImageType: "TIFF", ReadDpi: true})
		if imageIndex == nil {
			fmt.Println("Error registering image for PDF:", pdf.Error())

		}

		pdf.ImageOptions(TIF_DEST, 0, 0, imageWidth, imageHeight, false, gofpdf.ImageOptions{ImageType: "TIFF"}, 0, "")

		// 保存 PDF 文件
		err = pdf.OutputFileAndClose(PDF_DEST)
		if err != nil {
			fmt.Println("Error saving PDF file:", err)

		}

		fmt.Println("Conversion from TIF to PDF successful!")
	}
	//转为png
	command2 := "convert"
	args2 := []string{TIF_DEST, TBN_DEST}
	cmd2 := exec.Command(command2, args2...)
	err2 := cmd2.Run()
	if err2 != nil {
		fmt.Printf("执行tiff转png出错: %s\n", err2)
		fmt.Println("尝试使用golang转png...")
		// 读取 TIF 文件
		tifData, err := os.ReadFile(TIF_DEST)
		if err != nil {
			fmt.Println("Error reading TIF file:", err)
		}

		// 解码 TIF 数据
		img, err := tiff.Decode(bytes.NewReader(tifData))
		if err != nil {
			fmt.Println("Error decoding TIF image:", err)
		}

		// 创建输出 PNG 文件
		outfile, err := os.Create(TBN_DEST)
		if err != nil {
			fmt.Println("Error creating PNG file:", err)
		}
		defer outfile.Close()

		// 将图像以 PNG 格式写入文件
		if err := png.Encode(outfile, img); err != nil {
			fmt.Println("Error encoding PNG image:", err)
		}

		fmt.Println("Conversion from TIF to PNG successful!")
	}
	fmt.Printf("tiff转换完成")
	ScanEnd = "1"
	return 0, nil
}

// 获取DEST_DIR下的所有pdf的文件名
func getAllPDFFiles(folderPath string) []string {
	var pdfFiles []string

	// 遍历指定文件夹下的所有文件和子文件夹
	err := filepath.Walk(folderPath, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if !info.IsDir() && strings.HasSuffix(strings.ToLower(info.Name()), ".pdf") {
			// pdfFiles = append(pdfFiles, info.Name()) // 将 PDF 文件名添加到数组中
			fileName := strings.TrimSuffix(filepath.Base(info.Name()), ".pdf")
			pdfFiles = append(pdfFiles, fileName) // 将不带扩展名的 PDF 文件名添加到数组中
		}
		return nil
	})
	if err != nil {
		fmt.Println(err)
	}

	return pdfFiles
}

// ScanImageListing 结构表示扫描设备的列表
type ScanImageListing struct {
	Value string
	Name  string
}

// GetScanDevices 函数运行scanimage -L命令，并返回设备列表
func GetScanDevices() ([]ScanImageListing, error) {
	cmd := exec.Command("scanimage", "-L")
	output, err := cmd.CombinedOutput()
	if err != nil {
		return nil, err
	}

	lines := strings.Split(string(output), "\n")
	devices := make([]ScanImageListing, 0)

	for _, line := range lines {
		if strings.HasPrefix(line, "device") {
			deviceInfo := strings.Fields(line)
			deviceName := strings.Join(deviceInfo[1:], " ")
			//对设备名再处理
			deviceName = extractString(deviceName)
			device := ScanImageListing{Value: deviceName, Name: deviceName}
			devices = append(devices, device)
		}
	}

	return devices, nil
}

// 对设备名称处理
func extractString(input string) string {
	re := regexp.MustCompile("`([^']*)'")
	match := re.FindStringSubmatch(input)
	if len(match) > 1 {
		return match[1]
	}
	return input
}

// 读取本地json文件，获取该设备的扫描预期时间
// 定义存储数据结构体
type ScanDpi struct {
	Dpi300 string
	Dpi150 string
	Dpi100 string
	Dpi75  string
	Dpi60  string
	Dpi50  string
	Dpi43  string
	Dpi37  string
}

type ScanDevice struct {
	DeviceName     string
	DeviceDpiValue ScanDpi
}

func getScanTimeJSON(filepath string, scanDevice string, dpiValue string) float64 {
	jsonFile, err := os.Open(filepath) // 打开 json 文件
	if err != nil {
		log.Printf("open json file %v error [ %v ]\n", filepath, err)
		return -1.0
	}
	defer jsonFile.Close()

	var conf []ScanDevice
	decoder := json.NewDecoder(jsonFile) // 创建 json 解码器
	err = decoder.Decode(&conf)          // 解码 json 文件
	if err != nil {
		if err.Error() == "EOF" {
			fmt.Println("JSON文件内容为空")
			return 0.0
		}
		log.Printf("decode error [ %v ]\n", err)
		return -1.0
	} else {
		if len(conf) == 0 {
			fmt.Println("JSON文件内容为空")
			return 0.0
		}
		fmt.Printf("解码后的扫描时间json文件:\n%s\n", conf)
		for _, device := range conf {
			if device.DeviceName == scanDevice {
				switch dpiValue {
				case "Dpi300":
					// 找到匹配的设备和DPI值，可以根据需求获取对应的扫描时间并返回
					if device.DeviceDpiValue.Dpi300 == "" {
						return 0.0 //该分辨率首次运行
					}
					fmt.Printf("找到匹配的设备和DPI值，扫描时间为：%s\n", device.DeviceDpiValue.Dpi300)
					f, err := strconv.ParseFloat(device.DeviceDpiValue.Dpi300, 64)
					if err != nil {
						fmt.Println("float64转换失败：", err)
						return -1.0
					}
					return f // 替换为实际的扫描时间

				case "Dpi150":
					// 找到匹配的设备和DPI值，可以根据需求获取对应的扫描时间并返回
					if device.DeviceDpiValue.Dpi150 == "" {
						return 0.0 //该分辨率首次运行
					}
					fmt.Printf("找到匹配的设备和DPI值，扫描时间为：%s\n", device.DeviceDpiValue.Dpi150)
					f, err := strconv.ParseFloat(device.DeviceDpiValue.Dpi150, 64)
					if err != nil {
						fmt.Println("float64转换失败：", err)
						return -1.0
					}
					return f // 替换为实际的扫描时间

				case "Dpi100":
					// 找到匹配的设备和DPI值，可以根据需求获取对应的扫描时间并返回
					if device.DeviceDpiValue.Dpi100 == "" {
						return 0.0 //该分辨率首次运行
					}
					fmt.Printf("找到匹配的设备和DPI值，扫描时间为：%s\n", device.DeviceDpiValue.Dpi100)
					f, err := strconv.ParseFloat(device.DeviceDpiValue.Dpi100, 64)
					if err != nil {
						fmt.Println("float64转换失败：", err)
						return -1.0
					}
					return f // 替换为实际的扫描时间

				case "Dpi75":
					// 找到匹配的设备和DPI值，可以根据需求获取对应的扫描时间并返回
					if device.DeviceDpiValue.Dpi75 == "" {
						return 0.0 //该分辨率首次运行
					}
					fmt.Printf("找到匹配的设备和DPI值，扫描时间为：%s\n", device.DeviceDpiValue.Dpi75)
					f, err := strconv.ParseFloat(device.DeviceDpiValue.Dpi75, 64)
					if err != nil {
						fmt.Println("float64转换失败：", err)
						return -1.0
					}
					return f // 替换为实际的扫描时间

				case "Dpi60":
					// 找到匹配的设备和DPI值，可以根据需求获取对应的扫描时间并返回
					if device.DeviceDpiValue.Dpi60 == "" {
						return 0.0 //该分辨率首次运行
					}
					fmt.Printf("找到匹配的设备和DPI值，扫描时间为：%s\n", device.DeviceDpiValue.Dpi60)
					f, err := strconv.ParseFloat(device.DeviceDpiValue.Dpi60, 64)
					if err != nil {
						fmt.Println("float64转换失败：", err)
						return -1.0
					}
					return f // 替换为实际的扫描时间

				case "Dpi50":
					// 找到匹配的设备和DPI值，可以根据需求获取对应的扫描时间并返回
					if device.DeviceDpiValue.Dpi50 == "" {
						return 0.0 //该分辨率首次运行
					}
					fmt.Printf("找到匹配的设备和DPI值，扫描时间为：%s\n", device.DeviceDpiValue.Dpi50)
					f, err := strconv.ParseFloat(device.DeviceDpiValue.Dpi50, 64)
					if err != nil {
						fmt.Println("float64转换失败：", err)
						return -1.0
					}
					return f // 替换为实际的扫描时间

				case "Dpi43":
					// 找到匹配的设备和DPI值，可以根据需求获取对应的扫描时间并返回
					if device.DeviceDpiValue.Dpi43 == "" {
						return 0.0 //该分辨率首次运行
					}
					fmt.Printf("找到匹配的设备和DPI值，扫描时间为：%s\n", device.DeviceDpiValue.Dpi43)
					f, err := strconv.ParseFloat(device.DeviceDpiValue.Dpi43, 64)
					if err != nil {
						fmt.Println("float64转换失败：", err)
						return -1.0
					}
					return f // 替换为实际的扫描时间

				case "Dpi37":
					// 找到匹配的设备和DPI值，可以根据需求获取对应的扫描时间并返回
					if device.DeviceDpiValue.Dpi37 == "" {
						return 0.0 //该分辨率首次运行
					}
					fmt.Printf("找到匹配的设备和DPI值，扫描时间为：%s\n", device.DeviceDpiValue.Dpi37)
					f, err := strconv.ParseFloat(device.DeviceDpiValue.Dpi37, 64)
					if err != nil {
						fmt.Println("float64转换失败：", err)
						return -1.0
					}
					return f // 替换为实际的扫描时间

				}

			}
		}
		fmt.Printf("检索json完成")
		return -2.0
	}
}

// 将扫描时间写入本地json文件,下次直接调用
func setScanTimeJSON(scanTimeW float64, scanDevice string, dpiValue string, filepath string) bool {
	// 添加标记来标识是否找到了匹配的设备
	foundDevice := false
	// 读取已有的JSON内容
	jsonFileR, err := os.Open(filepath)
	if err != nil {
		log.Printf("open json file %v error [ %v ]\n", filepath, err)
		return false
	}
	defer jsonFileR.Close()

	var scanDevices []ScanDevice
	decoder := json.NewDecoder(jsonFileR)
	err = decoder.Decode(&scanDevices)
	if err != nil {
		if err.Error() == "EOF" {
			fmt.Println("JSON文件内容为空")
			scanDevices = make([]ScanDevice, 0) // 创建一个新的空数组
		} else {
			log.Printf("decode error [ %v ]\n", err)
			return false
		}
	}

	jsonFileW, err := os.Create(filepath) // 创建 json 文件
	if err != nil {
		log.Printf("create json file %v error [ %v ]\n", filepath, err)
		return false
	}
	defer jsonFileW.Close()

	for i, device := range scanDevices {
		if device.DeviceName == scanDevice {
			foundDevice = true
			switch dpiValue {
			case "Dpi300":
				converted_string := strconv.FormatFloat(scanTimeW, 'E', -1, 32)
				scanDevices[i].DeviceDpiValue.Dpi300 = converted_string

			case "Dpi150":
				converted_string := strconv.FormatFloat(scanTimeW, 'E', -1, 32)
				fmt.Printf("写入Dpi150时间%s...\n", converted_string)
				scanDevices[i].DeviceDpiValue.Dpi150 = converted_string

			case "Dpi100":
				converted_string := strconv.FormatFloat(scanTimeW, 'E', -1, 32)
				scanDevices[i].DeviceDpiValue.Dpi100 = converted_string

			case "Dpi75":
				converted_string := strconv.FormatFloat(scanTimeW, 'E', -1, 32)
				scanDevices[i].DeviceDpiValue.Dpi75 = converted_string

			case "Dpi60":
				converted_string := strconv.FormatFloat(scanTimeW, 'E', -1, 32)
				scanDevices[i].DeviceDpiValue.Dpi60 = converted_string

			case "Dpi50":
				converted_string := strconv.FormatFloat(scanTimeW, 'E', -1, 32)
				scanDevices[i].DeviceDpiValue.Dpi50 = converted_string

			case "Dpi43":
				converted_string := strconv.FormatFloat(scanTimeW, 'E', -1, 32)
				scanDevices[i].DeviceDpiValue.Dpi43 = converted_string

			case "Dpi37":
				converted_string := strconv.FormatFloat(scanTimeW, 'E', -1, 32)
				scanDevices[i].DeviceDpiValue.Dpi37 = converted_string
			}

		}
	}

	// 如果未找到匹配的设备，则创建新的设备并添加到 scanDevices 数组中
	if foundDevice == false {
		fmt.Println("发现新设备")
		newDevice := ScanDevice{
			DeviceName: scanDevice,
			DeviceDpiValue: ScanDpi{
				Dpi300: "",
				Dpi150: "",
				Dpi100: "",
				Dpi75:  "",
				Dpi60:  "",
				Dpi50:  "",
				Dpi43:  "",
				Dpi37:  "",
			},
		}
		switch dpiValue {
		case "Dpi300":
			converted_string := strconv.FormatFloat(scanTimeW, 'E', -1, 32)
			newDevice.DeviceDpiValue.Dpi300 = converted_string
		case "Dpi150":
			converted_string := strconv.FormatFloat(scanTimeW, 'E', -1, 32)
			newDevice.DeviceDpiValue.Dpi150 = converted_string
		case "Dpi100":
			converted_string := strconv.FormatFloat(scanTimeW, 'E', -1, 32)
			newDevice.DeviceDpiValue.Dpi100 = converted_string
		case "Dpi75":
			converted_string := strconv.FormatFloat(scanTimeW, 'E', -1, 32)
			newDevice.DeviceDpiValue.Dpi75 = converted_string
		case "Dpi60":
			converted_string := strconv.FormatFloat(scanTimeW, 'E', -1, 32)
			newDevice.DeviceDpiValue.Dpi60 = converted_string
		case "Dpi50":
			converted_string := strconv.FormatFloat(scanTimeW, 'E', -1, 32)
			newDevice.DeviceDpiValue.Dpi50 = converted_string
		case "Dpi43":
			converted_string := strconv.FormatFloat(scanTimeW, 'E', -1, 32)
			newDevice.DeviceDpiValue.Dpi43 = converted_string
		case "Dpi37":
			converted_string := strconv.FormatFloat(scanTimeW, 'E', -1, 32)
			newDevice.DeviceDpiValue.Dpi37 = converted_string
		}

		scanDevices = append(scanDevices, newDevice)
	}

	fmt.Println("存入的scanDevices:", scanDevices)
	encode := json.NewEncoder(jsonFileW) // 创建编码器
	err = encode.Encode(scanDevices)     // 编码
	if err != nil {
		log.Printf("encode error [ %v ]\n", err)
		return false
	}
	fmt.Printf("扫描时间写入本地json成功\n")
	return true
}

//***************************************

// 主函数
func main() {
	//初始化路由
	router := gin.Default()
	//加载html静态文件
	router.Static("/static", "./templates")
	//加载templates中所有模板文件, 使用不同目录下名称相同的模板,注意:一定要放在配置路由之前才得行
	//router.LoadHTMLGlob("templates/*")
	router.LoadHTMLFiles("templates/index.html", "templates/saneScan.html", "templates/showScanInfo.html", "templates/test.html")
	//加载pdf.js静态文件
	router.Static("/pdfjs", "./templates/pdfjs-4.0.379-dist")
	//加载扫描文件数据
	router.Static("/scanData", "./templates/scanData")

	//*************数据结构定义*************
	// 定义接收数据的结构体
	type ScanSetting struct {
		// binding:"required"修饰的字段，若接收为空值，则报错，是必须字段
		Device   string `form:"device" json:"device" uri:"device" xml:"device" binding:"required"`
		Dpi      string `form:"dpi" json:"dpi" uri:"dpi" xml:"dpi" binding:"required"`
		Mode     string `form:"mode" json:"mode" uri:"mode" xml:"mode" binding:"required"`
		FileName string `form:"filename" json:"filename" uri:"filename" xml:"filename" binding:"required"`
	}

	//*************************************

	//***********加载页面定义**************
	router.GET("/", func(c *gin.Context) {
		c.HTML(http.StatusOK, "index.html", gin.H{
			"title": "首页",
		})
		fmt.Printf("运行完成\n")
	})

	router.GET("/SANEScan", func(c *gin.Context) {
		//获取当前所有的pdf文件名
		pdfFilesArray := getAllPDFFiles(DEST_DIR)
		//获取当前的扫描设备列表
		devicesArray, err := GetScanDevices()
		if err != nil {
			fmt.Printf("执行GetScanDevices出错:%s\n", err)
		}
		c.HTML(http.StatusOK, "saneScan.html", gin.H{
			"title":      "扫描页",
			"itemList":   pdfFilesArray,
			"deviceList": devicesArray,
		})
		fmt.Printf("运行完成\n")
	})

	//扫描文件详情页
	router.GET("/showScanInfo", func(c *gin.Context) {
		//指定默认值
		//http://localhost:8080/showScanInfo 才会打印出来默认的值
		filename := c.DefaultQuery("filename", "noFind")
		if filename == "noFind" {
			//加载错误页
			c.HTML(http.StatusOK, "404.html", gin.H{
				"title": "错误页",
			})
		} else {
			//获取文件名
			filename = c.Query("filename")
			//加载展示页
			c.HTML(http.StatusOK, "showScanInfo.html", gin.H{
				"filename": filename,
			})
		}
	})

	router.GET("/test", func(c *gin.Context) {
		c.HTML(http.StatusOK, "test.html", gin.H{
			"title": "测试用页",
		})
	})

	router.GET("/test2", func(c *gin.Context) {
		c.File("./test.pdf")
		c.JSON(http.StatusOK, "done")
	})
	//*************************************

	//***********响应函数定义**************
	//开始执行SANE扫描
	router.POST("/SANEScanStart", func(c *gin.Context) {
		// 声明接收的变量
		var scan_setting ScanSetting
		// Bind()默认解析并绑定form格式
		// 根据请求头中content-type自动推断
		fmt.Printf("跳入扫描函数\n")
		if err := c.Bind(&scan_setting); err != nil {
			// 返回错误信息
			// gin.H封装了生成json数据的工具
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}
		//fmt.Printf("go后端成功接收到消息:%s , %s , %s, %s\n", scan_setting.Device, scan_setting.Dpi, scan_setting.Mode, scan_setting.FileName)
		fmt.Printf("收到来自前端的SANE扫描设置:\n设备名:%s\n分辨率:%s\n模式:%s\n文件名:%s\n", scan_setting.Device, scan_setting.Dpi, scan_setting.Mode, scan_setting.FileName)
		//判断当前扫描设备是否有扫描时间预置
		scanTime := getScanTimeJSON("./templates/scanTime.json", scan_setting.Device, "Dpi"+scan_setting.Dpi)
		switch scanTime {
		case 0.0:
			//表明首次运行该分辨率扫描
			fmt.Printf("该分辨率首次运行\n")
			ScanTimeExist = false
			//取当前时间
			ScanTimeStart = time.Now()
		case -1.0:
			//表明读取时间出错
			fmt.Printf("读取分辨率错误\n")
			ScanTimeExist = false
			c.JSON(http.StatusBadGateway, gin.H{"status": "400"})
		case -2.0:
			//表明检索完成，没有发现该分辨率
			fmt.Printf("json文件中没有该分辨率设置\n")
			ScanTimeExist = false
			c.JSON(http.StatusBadGateway, gin.H{"status": "400"})
		default:
			//取当前时间
			ScanTimeStart = time.Now()
			ScanTimeExist = true
			ScanTimeAll = scanTime //赋时间给全局变量
			fmt.Printf("取到扫描时间:%f\n", ScanTimeAll)
		}

		fmt.Printf("SANE开始扫描...\n")
		//执行ScanProgress
		_, err := ScanProgress(scan_setting.Device, scan_setting.Dpi, scan_setting.Mode, scan_setting.FileName)
		if ScanTimeExist == false && scanTime == 0.0 {
			ScanTimeEnd = time.Now() //取终止时间
			// 计算时间差
			elapsed := ScanTimeEnd.Sub(ScanTimeStart)
			elapsedTimeSeconds := elapsed.Seconds()

			ScanTimeAll = elapsedTimeSeconds
			//将该分辨率扫描时间存入本地
			fmt.Printf("扫描时间存入本地...\n")
			setScanTimeJSON(ScanTimeAll, scan_setting.Device, "Dpi"+scan_setting.Dpi, "./templates/scanTime.json")
		} else {
			if ScanTimeExist == true {
				fmt.Printf("获取到本地扫描时间\n")
			} else {
				fmt.Printf("执行读取扫描时间出错\n")
			}
		}
		if err != nil {
			fmt.Printf("执行ScanProgress出错:%s", err)
			c.JSON(http.StatusBadGateway, gin.H{"status": "400"})
		}
		c.JSON(http.StatusOK, gin.H{"status": "200"})
	})

	//获取扫描进度函数
	router.GET("/GetProcess", func(c *gin.Context) {
		var isProgressExist = "0"
		if ScanTimeExist == true {
			var scantimeNow time.Time
			scantimeNow = time.Now()
			// 计算时间差
			elapsed := scantimeNow.Sub(ScanTimeStart)
			elapsedTimeSeconds := elapsed.Seconds()

			ScanProgressValue = (elapsedTimeSeconds / ScanTimeAll) * 100.0
			isProgressExist = "1"
			if ScanProgressValue > 100.0 {
				ScanProgressValue = 100.0
			}
			fmt.Printf("当前时间差:%f\n当前全程扫描时间:%f\n当前进度百分比:%f\n", elapsedTimeSeconds, ScanTimeAll, ScanProgressValue)
		} else {
			ScanProgressValue = 0.0
			isProgressExist = "0"
		}
		//返回扫描进度
		c.JSON(http.StatusOK, gin.H{"scanProcess": strconv.FormatFloat(ScanProgressValue, 'f', 0, 64), "isProgressExist": isProgressExist, "ScanEnd": ScanEnd})
	})

	//删除扫描文件
	router.GET("/remove", func(c *gin.Context) {
		filename := c.Query("filename")
		fmt.Printf("接收到数据%s\n", filename)
		//删除文件
		os.Remove("./templates/scanData/" + filename + ".pdf")
		os.Remove("./templates/scanData/" + filename + ".tiff")
		os.Remove("./templates/scanData/thumb/" + filename + ".png")
		// fmt.Printf("调试：删除文件%s\n", filename)
		c.JSON(http.StatusOK, gin.H{"status": "200"})
		fmt.Printf("文件删除成功\n")
	})

	//获取扫描设备列表
	router.GET("/getDevicesList", func(c *gin.Context) {
		// fmt.Printf("获取设备列表\n")
		devices, err := GetScanDevices()
		fmt.Print("扫描设备列表:\n", devices, "\n")
		if err != nil {
			fmt.Printf("执行GetScanDevices出错:%s\n", err)
			c.JSON(http.StatusBadGateway, gin.H{"list": ""})
		}
		c.JSON(http.StatusOK, gin.H{"list": devices,
			"status": "200"})
	})

	//*************************************

	router.Run(":" + POST)
}
=======
package main

import (
	"bufio"
	"bytes"
	"encoding/json"
	"fmt"
	_ "image/jpeg"
	"image/png"
	"io"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/jung-kurt/gofpdf"
	"golang.org/x/image/tiff"

	"github.com/gin-gonic/gin"
)

// **************全局变量定义**************
// 定义全局扫描进度变量ScanProgressValue
var ScanProgressValue float64 = 0.0

// 定义全局扫描文件存储目录变量DEST_DIR
var DEST_DIR string = "./templates/scanData"

// 定义全局网页端口变量PORT
var POST string = "7575"

// 定义全局扫描时间是否存在检测变量
var ScanTimeExist bool = false

// 定义全局扫描时间变量
var ScanTimeStart time.Time
var ScanTimeEnd time.Time
var ScanTimeAll float64

// 定义全局扫描流程结束标识符
var ScanEnd string = "0"

//***************************************

// *************后端函数定义**************
// 执行SANE扫描cmd命令并返回实时扫描进度
func ScanProgress(device string, dpi string, mode string, fileName string) (float64, error) {
	ScanEnd = "0"
	//声明TIF_DEST变量
	TIF_DEST := DEST_DIR + "/" + fileName + ".tiff"
	//声明PDF_DEST变量
	PDF_DEST := DEST_DIR + "/" + fileName + ".pdf"
	//声明TBN_DEST变量
	TBN_DEST := DEST_DIR + "/thumb/" + fileName + ".png"
	cmdName := "scanimage"
	cmdArgs := []string{"--progress", "--device-name", device, "--resolution", dpi, "--mode", mode, "--format", "tiff", "--output-file", TIF_DEST} // --device-name设备名称 --resolution分辨率 --mode扫描模式 --progress命令用于显示扫描的进度

	// 打印即将执行的命令
	fmt.Printf("将要执行的命令：%s %s\n", cmdName, strings.Join(cmdArgs, " "))
	ScanProgressValue = 60.00
	cmd := exec.Command(cmdName, cmdArgs...)
	var stderr bytes.Buffer
	cmd.Stderr = &stderr
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		fmt.Printf("执行cmd.StdoutPipe()出错:%s\n", err)
		fmt.Println(fmt.Sprint(err) + ": " + stderr.String())
		return 0, err
	}

	if err := cmd.Start(); err != nil {
		fmt.Printf("执行cmd.Start()出错:%s\n", err)
		fmt.Println(fmt.Sprint(err) + ": " + stderr.String())
		return 0, err
	}

	go func() {
		reader := bufio.NewReader(stdout)
		for {
			line, err := reader.ReadString('\n')
			fmt.Printf("当前行内容：%s\n", line) // 添加调试输出

			if err != nil || err == io.EOF {
				break
			}

			if strings.Contains(line, "Progress:") {
				fmt.Printf("发现进度信息：%s\n", line) // 添加调试输出

				progressStr := strings.Split(line, ":")[1]
				// 去除百分号
				progressStr = strings.TrimSpace(progressStr[:len(progressStr)-1])

				progress, err := strconv.ParseFloat(progressStr, 64)
				if err != nil {
					fmt.Println("解析进度信息时出现错误:", err) // 添加调试输出
					// 如果解析出错，可以尝试打印 progressStr 看看原始内容
					continue
				}

				fmt.Printf("当前 ScanProgressValue：%f\n", progress)
				// 将进度保存到全局变量
				ScanProgressValue = progress
			}
		}
	}()

	if err := cmd.Wait(); err != nil {
		fmt.Printf("执行cmd.Wait()出错:%s\n", err)
		fmt.Println(fmt.Sprint(err) + ": " + stderr.String())
		return 0, err
	}
	ScanProgressValue = 100.00
	fmt.Printf("tiff格式转换...")
	//将获得的tiff转换
	//转为pdf
	command1 := "convert"
	args1 := []string{TIF_DEST, PDF_DEST}
	cmd1 := exec.Command(command1, args1...)
	err1 := cmd1.Run()
	if err1 != nil {
		fmt.Printf("执行tiff转pdf出错: %s", err1)
		fmt.Println("尝试使用golang转换pdf...")
		// 读取 TIF 文件
		tifData, err := os.ReadFile(TIF_DEST)
		if err != nil {
			fmt.Println("Error reading TIF file:", err)

		}

		// 解码 TIF 数据
		img, err := tiff.Decode(bytes.NewReader(tifData))
		if err != nil {
			fmt.Println("Error decoding TIF image:", err)

		}

		// 获取 TIF 图像的宽度和高度
		bounds := img.Bounds()
		imageWidth := float64(bounds.Dx())
		imageHeight := float64(bounds.Dy())

		// 创建 PDF 文件
		pdf := gofpdf.New("P", "mm", "A4", "")
		pdf.AddPage()

		// 将 TIF 图像转换为 PDF 图像
		imageIndex := pdf.RegisterImageOptions(TIF_DEST, gofpdf.ImageOptions{ImageType: "TIFF", ReadDpi: true})
		if imageIndex == nil {
			fmt.Println("Error registering image for PDF:", pdf.Error())

		}

		pdf.ImageOptions(TIF_DEST, 0, 0, imageWidth, imageHeight, false, gofpdf.ImageOptions{ImageType: "TIFF"}, 0, "")

		// 保存 PDF 文件
		err = pdf.OutputFileAndClose(PDF_DEST)
		if err != nil {
			fmt.Println("Error saving PDF file:", err)

		}

		fmt.Println("Conversion from TIF to PDF successful!")
	}
	//转为png
	command2 := "convert"
	args2 := []string{TIF_DEST, TBN_DEST}
	cmd2 := exec.Command(command2, args2...)
	err2 := cmd2.Run()
	if err2 != nil {
		fmt.Printf("执行tiff转png出错: %s\n", err2)
		fmt.Println("尝试使用golang转png...")
		// 读取 TIF 文件
		tifData, err := os.ReadFile(TIF_DEST)
		if err != nil {
			fmt.Println("Error reading TIF file:", err)
		}

		// 解码 TIF 数据
		img, err := tiff.Decode(bytes.NewReader(tifData))
		if err != nil {
			fmt.Println("Error decoding TIF image:", err)
		}

		// 创建输出 PNG 文件
		outfile, err := os.Create(TBN_DEST)
		if err != nil {
			fmt.Println("Error creating PNG file:", err)
		}
		defer outfile.Close()

		// 将图像以 PNG 格式写入文件
		if err := png.Encode(outfile, img); err != nil {
			fmt.Println("Error encoding PNG image:", err)
		}

		fmt.Println("Conversion from TIF to PNG successful!")
	}
	fmt.Printf("tiff转换完成")
	ScanEnd = "1"
	return 0, nil
}

// 获取DEST_DIR下的所有pdf的文件名
func getAllPDFFiles(folderPath string) []string {
	var pdfFiles []string

	// 遍历指定文件夹下的所有文件和子文件夹
	err := filepath.Walk(folderPath, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if !info.IsDir() && strings.HasSuffix(strings.ToLower(info.Name()), ".pdf") {
			// pdfFiles = append(pdfFiles, info.Name()) // 将 PDF 文件名添加到数组中
			fileName := strings.TrimSuffix(filepath.Base(info.Name()), ".pdf")
			pdfFiles = append(pdfFiles, fileName) // 将不带扩展名的 PDF 文件名添加到数组中
		}
		return nil
	})
	if err != nil {
		fmt.Println(err)
	}

	return pdfFiles
}

// ScanImageListing 结构表示扫描设备的列表
type ScanImageListing struct {
	Value string
	Name  string
}

// GetScanDevices 函数运行scanimage -L命令，并返回设备列表
func GetScanDevices() ([]ScanImageListing, error) {
	cmd := exec.Command("scanimage", "-L")
	output, err := cmd.CombinedOutput()
	if err != nil {
		return nil, err
	}

	lines := strings.Split(string(output), "\n")
	devices := make([]ScanImageListing, 0)

	for _, line := range lines {
		if strings.HasPrefix(line, "device") {
			deviceInfo := strings.Fields(line)
			deviceName := strings.Join(deviceInfo[1:], " ")
			//对设备名再处理
			deviceName = extractString(deviceName)
			device := ScanImageListing{Value: deviceName, Name: deviceName}
			devices = append(devices, device)
		}
	}

	return devices, nil
}

// 对设备名称处理
func extractString(input string) string {
	re := regexp.MustCompile("`([^']*)'")
	match := re.FindStringSubmatch(input)
	if len(match) > 1 {
		return match[1]
	}
	return input
}

// 读取本地json文件，获取该设备的扫描预期时间
// 定义存储数据结构体
type ScanDpi struct {
	Dpi300 string
	Dpi150 string
	Dpi100 string
	Dpi75  string
	Dpi60  string
	Dpi50  string
	Dpi43  string
	Dpi37  string
}

type ScanDevice struct {
	DeviceName     string
	DeviceDpiValue ScanDpi
}

func getScanTimeJSON(filepath string, scanDevice string, dpiValue string) float64 {
	jsonFile, err := os.Open(filepath) // 打开 json 文件
	if err != nil {
		log.Printf("open json file %v error [ %v ]\n", filepath, err)
		return -1.0
	}
	defer jsonFile.Close()

	var conf []ScanDevice
	decoder := json.NewDecoder(jsonFile) // 创建 json 解码器
	err = decoder.Decode(&conf)          // 解码 json 文件
	if err != nil {
		if err.Error() == "EOF" {
			fmt.Println("JSON文件内容为空")
			return 0.0
		}
		log.Printf("decode error [ %v ]\n", err)
		return -1.0
	} else {
		if len(conf) == 0 {
			fmt.Println("JSON文件内容为空")
			return 0.0
		}
		fmt.Printf("解码后的扫描时间json文件:\n%s\n", conf)
		for _, device := range conf {
			if device.DeviceName == scanDevice {
				switch dpiValue {
				case "Dpi300":
					// 找到匹配的设备和DPI值，可以根据需求获取对应的扫描时间并返回
					if device.DeviceDpiValue.Dpi300 == "" {
						return 0.0 //该分辨率首次运行
					}
					fmt.Printf("找到匹配的设备和DPI值，扫描时间为：%s\n", device.DeviceDpiValue.Dpi300)
					f, err := strconv.ParseFloat(device.DeviceDpiValue.Dpi300, 64)
					if err != nil {
						fmt.Println("float64转换失败：", err)
						return -1.0
					}
					return f // 替换为实际的扫描时间

				case "Dpi150":
					// 找到匹配的设备和DPI值，可以根据需求获取对应的扫描时间并返回
					if device.DeviceDpiValue.Dpi150 == "" {
						return 0.0 //该分辨率首次运行
					}
					fmt.Printf("找到匹配的设备和DPI值，扫描时间为：%s\n", device.DeviceDpiValue.Dpi150)
					f, err := strconv.ParseFloat(device.DeviceDpiValue.Dpi150, 64)
					if err != nil {
						fmt.Println("float64转换失败：", err)
						return -1.0
					}
					return f // 替换为实际的扫描时间

				case "Dpi100":
					// 找到匹配的设备和DPI值，可以根据需求获取对应的扫描时间并返回
					if device.DeviceDpiValue.Dpi100 == "" {
						return 0.0 //该分辨率首次运行
					}
					fmt.Printf("找到匹配的设备和DPI值，扫描时间为：%s\n", device.DeviceDpiValue.Dpi100)
					f, err := strconv.ParseFloat(device.DeviceDpiValue.Dpi100, 64)
					if err != nil {
						fmt.Println("float64转换失败：", err)
						return -1.0
					}
					return f // 替换为实际的扫描时间

				case "Dpi75":
					// 找到匹配的设备和DPI值，可以根据需求获取对应的扫描时间并返回
					if device.DeviceDpiValue.Dpi75 == "" {
						return 0.0 //该分辨率首次运行
					}
					fmt.Printf("找到匹配的设备和DPI值，扫描时间为：%s\n", device.DeviceDpiValue.Dpi75)
					f, err := strconv.ParseFloat(device.DeviceDpiValue.Dpi75, 64)
					if err != nil {
						fmt.Println("float64转换失败：", err)
						return -1.0
					}
					return f // 替换为实际的扫描时间

				case "Dpi60":
					// 找到匹配的设备和DPI值，可以根据需求获取对应的扫描时间并返回
					if device.DeviceDpiValue.Dpi60 == "" {
						return 0.0 //该分辨率首次运行
					}
					fmt.Printf("找到匹配的设备和DPI值，扫描时间为：%s\n", device.DeviceDpiValue.Dpi60)
					f, err := strconv.ParseFloat(device.DeviceDpiValue.Dpi60, 64)
					if err != nil {
						fmt.Println("float64转换失败：", err)
						return -1.0
					}
					return f // 替换为实际的扫描时间

				case "Dpi50":
					// 找到匹配的设备和DPI值，可以根据需求获取对应的扫描时间并返回
					if device.DeviceDpiValue.Dpi50 == "" {
						return 0.0 //该分辨率首次运行
					}
					fmt.Printf("找到匹配的设备和DPI值，扫描时间为：%s\n", device.DeviceDpiValue.Dpi50)
					f, err := strconv.ParseFloat(device.DeviceDpiValue.Dpi50, 64)
					if err != nil {
						fmt.Println("float64转换失败：", err)
						return -1.0
					}
					return f // 替换为实际的扫描时间

				case "Dpi43":
					// 找到匹配的设备和DPI值，可以根据需求获取对应的扫描时间并返回
					if device.DeviceDpiValue.Dpi43 == "" {
						return 0.0 //该分辨率首次运行
					}
					fmt.Printf("找到匹配的设备和DPI值，扫描时间为：%s\n", device.DeviceDpiValue.Dpi43)
					f, err := strconv.ParseFloat(device.DeviceDpiValue.Dpi43, 64)
					if err != nil {
						fmt.Println("float64转换失败：", err)
						return -1.0
					}
					return f // 替换为实际的扫描时间

				case "Dpi37":
					// 找到匹配的设备和DPI值，可以根据需求获取对应的扫描时间并返回
					if device.DeviceDpiValue.Dpi37 == "" {
						return 0.0 //该分辨率首次运行
					}
					fmt.Printf("找到匹配的设备和DPI值，扫描时间为：%s\n", device.DeviceDpiValue.Dpi37)
					f, err := strconv.ParseFloat(device.DeviceDpiValue.Dpi37, 64)
					if err != nil {
						fmt.Println("float64转换失败：", err)
						return -1.0
					}
					return f // 替换为实际的扫描时间

				}

			}
		}
		fmt.Printf("检索json完成")
		return -2.0
	}
}

// 将扫描时间写入本地json文件,下次直接调用
func setScanTimeJSON(scanTimeW float64, scanDevice string, dpiValue string, filepath string) bool {
	// 添加标记来标识是否找到了匹配的设备
	foundDevice := false
	// 读取已有的JSON内容
	jsonFileR, err := os.Open(filepath)
	if err != nil {
		log.Printf("open json file %v error [ %v ]\n", filepath, err)
		return false
	}
	defer jsonFileR.Close()

	var scanDevices []ScanDevice
	decoder := json.NewDecoder(jsonFileR)
	err = decoder.Decode(&scanDevices)
	if err != nil {
		if err.Error() == "EOF" {
			fmt.Println("JSON文件内容为空")
			scanDevices = make([]ScanDevice, 0) // 创建一个新的空数组
		} else {
			log.Printf("decode error [ %v ]\n", err)
			return false
		}
	}

	jsonFileW, err := os.Create(filepath) // 创建 json 文件
	if err != nil {
		log.Printf("create json file %v error [ %v ]\n", filepath, err)
		return false
	}
	defer jsonFileW.Close()

	for i, device := range scanDevices {
		if device.DeviceName == scanDevice {
			foundDevice = true
			switch dpiValue {
			case "Dpi300":
				converted_string := strconv.FormatFloat(scanTimeW, 'E', -1, 32)
				scanDevices[i].DeviceDpiValue.Dpi300 = converted_string

			case "Dpi150":
				converted_string := strconv.FormatFloat(scanTimeW, 'E', -1, 32)
				fmt.Printf("写入Dpi150时间%s...\n", converted_string)
				scanDevices[i].DeviceDpiValue.Dpi150 = converted_string

			case "Dpi100":
				converted_string := strconv.FormatFloat(scanTimeW, 'E', -1, 32)
				scanDevices[i].DeviceDpiValue.Dpi100 = converted_string

			case "Dpi75":
				converted_string := strconv.FormatFloat(scanTimeW, 'E', -1, 32)
				scanDevices[i].DeviceDpiValue.Dpi75 = converted_string

			case "Dpi60":
				converted_string := strconv.FormatFloat(scanTimeW, 'E', -1, 32)
				scanDevices[i].DeviceDpiValue.Dpi60 = converted_string

			case "Dpi50":
				converted_string := strconv.FormatFloat(scanTimeW, 'E', -1, 32)
				scanDevices[i].DeviceDpiValue.Dpi50 = converted_string

			case "Dpi43":
				converted_string := strconv.FormatFloat(scanTimeW, 'E', -1, 32)
				scanDevices[i].DeviceDpiValue.Dpi43 = converted_string

			case "Dpi37":
				converted_string := strconv.FormatFloat(scanTimeW, 'E', -1, 32)
				scanDevices[i].DeviceDpiValue.Dpi37 = converted_string
			}

		}
	}

	// 如果未找到匹配的设备，则创建新的设备并添加到 scanDevices 数组中
	if foundDevice == false {
		fmt.Println("发现新设备")
		newDevice := ScanDevice{
			DeviceName: scanDevice,
			DeviceDpiValue: ScanDpi{
				Dpi300: "",
				Dpi150: "",
				Dpi100: "",
				Dpi75:  "",
				Dpi60:  "",
				Dpi50:  "",
				Dpi43:  "",
				Dpi37:  "",
			},
		}
		switch dpiValue {
		case "Dpi300":
			converted_string := strconv.FormatFloat(scanTimeW, 'E', -1, 32)
			newDevice.DeviceDpiValue.Dpi300 = converted_string
		case "Dpi150":
			converted_string := strconv.FormatFloat(scanTimeW, 'E', -1, 32)
			newDevice.DeviceDpiValue.Dpi150 = converted_string
		case "Dpi100":
			converted_string := strconv.FormatFloat(scanTimeW, 'E', -1, 32)
			newDevice.DeviceDpiValue.Dpi100 = converted_string
		case "Dpi75":
			converted_string := strconv.FormatFloat(scanTimeW, 'E', -1, 32)
			newDevice.DeviceDpiValue.Dpi75 = converted_string
		case "Dpi60":
			converted_string := strconv.FormatFloat(scanTimeW, 'E', -1, 32)
			newDevice.DeviceDpiValue.Dpi60 = converted_string
		case "Dpi50":
			converted_string := strconv.FormatFloat(scanTimeW, 'E', -1, 32)
			newDevice.DeviceDpiValue.Dpi50 = converted_string
		case "Dpi43":
			converted_string := strconv.FormatFloat(scanTimeW, 'E', -1, 32)
			newDevice.DeviceDpiValue.Dpi43 = converted_string
		case "Dpi37":
			converted_string := strconv.FormatFloat(scanTimeW, 'E', -1, 32)
			newDevice.DeviceDpiValue.Dpi37 = converted_string
		}

		scanDevices = append(scanDevices, newDevice)
	}

	fmt.Println("存入的scanDevices:", scanDevices)
	encode := json.NewEncoder(jsonFileW) // 创建编码器
	err = encode.Encode(scanDevices)     // 编码
	if err != nil {
		log.Printf("encode error [ %v ]\n", err)
		return false
	}
	fmt.Printf("扫描时间写入本地json成功\n")
	return true
}

//***************************************

// 主函数
func main() {
	//初始化路由
	router := gin.Default()
	//加载html静态文件
	router.Static("/static", "./templates")
	//加载templates中所有模板文件, 使用不同目录下名称相同的模板,注意:一定要放在配置路由之前才得行
	//router.LoadHTMLGlob("templates/*")
	router.LoadHTMLFiles("templates/index.html", "templates/saneScan.html", "templates/showScanInfo.html", "templates/test.html")
	//加载pdf.js静态文件
	router.Static("/pdfjs", "./templates/pdfjs-4.0.379-dist")
	//加载扫描文件数据
	router.Static("/scanData", "./templates/scanData")

	//*************数据结构定义*************
	// 定义接收数据的结构体
	type ScanSetting struct {
		// binding:"required"修饰的字段，若接收为空值，则报错，是必须字段
		Device   string `form:"device" json:"device" uri:"device" xml:"device" binding:"required"`
		Dpi      string `form:"dpi" json:"dpi" uri:"dpi" xml:"dpi" binding:"required"`
		Mode     string `form:"mode" json:"mode" uri:"mode" xml:"mode" binding:"required"`
		FileName string `form:"filename" json:"filename" uri:"filename" xml:"filename" binding:"required"`
	}

	//*************************************

	//***********加载页面定义**************
	router.GET("/", func(c *gin.Context) {
		c.HTML(http.StatusOK, "index.html", gin.H{
			"title": "首页",
		})
		fmt.Printf("运行完成\n")
	})

	router.GET("/SANEScan", func(c *gin.Context) {
		//获取当前所有的pdf文件名
		pdfFilesArray := getAllPDFFiles(DEST_DIR)
		//获取当前的扫描设备列表
		devicesArray, err := GetScanDevices()
		if err != nil {
			fmt.Printf("执行GetScanDevices出错:%s\n", err)
		}
		c.HTML(http.StatusOK, "saneScan.html", gin.H{
			"title":      "扫描页",
			"itemList":   pdfFilesArray,
			"deviceList": devicesArray,
		})
		fmt.Printf("运行完成\n")
	})

	//扫描文件详情页
	router.GET("/showScanInfo", func(c *gin.Context) {
		//指定默认值
		//http://localhost:8080/showScanInfo 才会打印出来默认的值
		filename := c.DefaultQuery("filename", "noFind")
		if filename == "noFind" {
			//加载错误页
			c.HTML(http.StatusOK, "404.html", gin.H{
				"title": "错误页",
			})
		} else {
			//获取文件名
			filename = c.Query("filename")
			//加载展示页
			c.HTML(http.StatusOK, "showScanInfo.html", gin.H{
				"filename": filename,
			})
		}
	})

	router.GET("/test", func(c *gin.Context) {
		c.HTML(http.StatusOK, "test.html", gin.H{
			"title": "测试用页",
		})
	})

	router.GET("/test2", func(c *gin.Context) {
		c.File("./test.pdf")
		c.JSON(http.StatusOK, "done")
	})
	//*************************************

	//***********响应函数定义**************
	//开始执行SANE扫描
	router.POST("/SANEScanStart", func(c *gin.Context) {
		// 声明接收的变量
		var scan_setting ScanSetting
		// Bind()默认解析并绑定form格式
		// 根据请求头中content-type自动推断
		fmt.Printf("跳入扫描函数\n")
		if err := c.Bind(&scan_setting); err != nil {
			// 返回错误信息
			// gin.H封装了生成json数据的工具
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}
		//fmt.Printf("go后端成功接收到消息:%s , %s , %s, %s\n", scan_setting.Device, scan_setting.Dpi, scan_setting.Mode, scan_setting.FileName)
		fmt.Printf("收到来自前端的SANE扫描设置:\n设备名:%s\n分辨率:%s\n模式:%s\n文件名:%s\n", scan_setting.Device, scan_setting.Dpi, scan_setting.Mode, scan_setting.FileName)
		//判断当前扫描设备是否有扫描时间预置
		scanTime := getScanTimeJSON("./templates/scanTime.json", scan_setting.Device, "Dpi"+scan_setting.Dpi)
		switch scanTime {
		case 0.0:
			//表明首次运行该分辨率扫描
			fmt.Printf("该分辨率首次运行\n")
			ScanTimeExist = false
			//取当前时间
			ScanTimeStart = time.Now()
		case -1.0:
			//表明读取时间出错
			fmt.Printf("读取分辨率错误\n")
			ScanTimeExist = false
			c.JSON(http.StatusBadGateway, gin.H{"status": "400"})
		case -2.0:
			//表明检索完成，没有发现该分辨率
			fmt.Printf("json文件中没有该分辨率设置\n")
			ScanTimeExist = false
			c.JSON(http.StatusBadGateway, gin.H{"status": "400"})
		default:
			//取当前时间
			ScanTimeStart = time.Now()
			ScanTimeExist = true
			ScanTimeAll = scanTime //赋时间给全局变量
			fmt.Printf("取到扫描时间:%f\n", ScanTimeAll)
		}

		fmt.Printf("SANE开始扫描...\n")
		//执行ScanProgress
		_, err := ScanProgress(scan_setting.Device, scan_setting.Dpi, scan_setting.Mode, scan_setting.FileName)
		if ScanTimeExist == false && scanTime == 0.0 {
			ScanTimeEnd = time.Now() //取终止时间
			// 计算时间差
			elapsed := ScanTimeEnd.Sub(ScanTimeStart)
			elapsedTimeSeconds := elapsed.Seconds()

			ScanTimeAll = elapsedTimeSeconds
			//将该分辨率扫描时间存入本地
			fmt.Printf("扫描时间存入本地...\n")
			setScanTimeJSON(ScanTimeAll, scan_setting.Device, "Dpi"+scan_setting.Dpi, "./templates/scanTime.json")
		} else {
			if ScanTimeExist == true {
				fmt.Printf("获取到本地扫描时间\n")
			} else {
				fmt.Printf("执行读取扫描时间出错\n")
			}
		}
		if err != nil {
			fmt.Printf("执行ScanProgress出错:%s", err)
			c.JSON(http.StatusBadGateway, gin.H{"status": "400"})
		}
		c.JSON(http.StatusOK, gin.H{"status": "200"})
	})

	//获取扫描进度函数
	router.GET("/GetProcess", func(c *gin.Context) {
		var isProgressExist = "0"
		if ScanTimeExist == true {
			var scantimeNow time.Time
			scantimeNow = time.Now()
			// 计算时间差
			elapsed := scantimeNow.Sub(ScanTimeStart)
			elapsedTimeSeconds := elapsed.Seconds()

			ScanProgressValue = (elapsedTimeSeconds / ScanTimeAll) * 100.0
			isProgressExist = "1"
			if ScanProgressValue > 100.0 {
				ScanProgressValue = 100.0
			}
			fmt.Printf("当前时间差:%f\n当前全程扫描时间:%f\n当前进度百分比:%f\n", elapsedTimeSeconds, ScanTimeAll, ScanProgressValue)
		} else {
			ScanProgressValue = 0.0
			isProgressExist = "0"
		}
		//返回扫描进度
		c.JSON(http.StatusOK, gin.H{"scanProcess": strconv.FormatFloat(ScanProgressValue, 'f', 0, 64), "isProgressExist": isProgressExist, "ScanEnd": ScanEnd})
	})

	//删除扫描文件
	router.GET("/remove", func(c *gin.Context) {
		filename := c.Query("filename")
		fmt.Printf("接收到数据%s\n", filename)
		//删除文件
		os.Remove("./templates/scanData/" + filename + ".pdf")
		os.Remove("./templates/scanData/" + filename + ".tiff")
		os.Remove("./templates/scanData/thumb/" + filename + ".png")
		// fmt.Printf("调试：删除文件%s\n", filename)
		c.JSON(http.StatusOK, gin.H{"status": "200"})
		fmt.Printf("文件删除成功\n")
	})

	//获取扫描设备列表
	router.GET("/getDevicesList", func(c *gin.Context) {
		// fmt.Printf("获取设备列表\n")
		devices, err := GetScanDevices()
		fmt.Print("扫描设备列表:\n", devices, "\n")
		if err != nil {
			fmt.Printf("执行GetScanDevices出错:%s\n", err)
			c.JSON(http.StatusBadGateway, gin.H{"list": ""})
		}
		c.JSON(http.StatusOK, gin.H{"list": devices,
			"status": "200"})
	})

	//*************************************

	router.Run(":" + POST)
}
>>>>>>> 147ebf1 (第1次提交)
